perm filename IOSAIL.BTH[UP,DOC]3 blob
sn#359338 filedate 1978-06-08 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00018 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 Changes to IOSAIL.
C00008 00003 Introduction.
C00010 00004 SPACE,TAB,BELL,FORMFD,LF,CR,CRLF,!,PROC,REF,THRU,UPTO,BEGINLOOP.
C00014 00005 NULLSTRING,CVBS,ALPHA,NUMER,MEMLOC,LOWBOUND,UPBOUND,NUMDIM.
C00017 00006 DEBUG,BUGON,BUGOFF.
C00023 00007 YES,NO,NUMERIC,LOWERCASE,UPPERCASE,ALPHABETIC,ALPHAMERIC.
C00025 00008 CAPITALIZE.
C00026 00009 ROUND.
C00027 00010 A discussion of channels.
C00030 00011 OPENREAD,OPENWRITE,CLOSEFILE,CLOSEALL.
C00033 00012 Filenames.
C00034 00013 The reads: LINE,INTEGER,REAL,STRING,WORD,YESNO,BUFFER,READ,RDTTY.
C00040 00014 EOF.
C00042 00015 GETPROMPT,SETPROMPT.
C00044 00016 SETREADER,GETREADER.
C00046 00017 SETECHO.
C00047 00018 TERM!PRINT!(ON | OFF),FILE!PRINT!(ON | OFF),FILE!PRINT!CLOSE.
C00049 ENDMK
C⊗;
Changes to IOSAIL.
∂6/8/78 -- WRITE FILE LOOKUP FIXED
A bug in iosail.sai which prohibited writefile retries has been fixed.
(LOOKUP→ENTER in the retry section.)
∂5/14/78 -- DOCUMENTATION JUSTIFICATION CLEANED UP
Up to this point there were a couple of justification patterns in
the text of IOSAIL.BTH[UP,DOC]. These were made consistent:
E format 10,0,74,-1. (Note the Changes page was not changed.)
∂4/28/78 -- LOADER BUG FIXED
The names FILE!PRINT!ON,FILE!PRINT!OFF,FILE!PRINT!CLOSE are too long
to be distinguished by the loader (since they were moved to IOSAIL.SAI)
therefore the procedures were renamed to be !!FPON,!!FPOFF,!!FPC and
the long names became macros in .HDR calling these new names for
the procedures. The change should be transparent to the user except
that the new bang-bang (!!) names of course become "reserved words".
∂4/27/78 -- FILE!PRINT!ON,FILE!PRINT!OFF,FILE!PRINT!CLOSE,CLOSEALL
have been moved from macros in .hdr to procedures in .sai to
permit PROFILE to make more reasonable output for these features.
In addition CLOSEALL now closes a SETPRINT file that may be open.
∂4/25/78 -- IOSAIL.DOC[107,bth] ==> IOSAIL.BTH[up,doc]
IOSAIL.HDR[107,bth] ==> IOSAIL.HDR[sub,sys]
IOSAIL.REL[107,bth] ==> IOSAIL.REL[sub,sys]
IOSAIL.SAI[107,bth] ==> IOSAIL.SAI[sub,sys]
∂2/23/78 -- openread and openwrite bug fixed
prompting for filenames in openread and openwrite will now
work correctly even with setprint in use (due to changing a
print to an outstr).
∂2/21/78 -- new macros
newr=new!record
nullr=null!record
∂2/21/78 -- ROUND
new ROUND function see iosail.doc
∂2/21/78 -- READINTEGER "fixed"
READINTEGER has been changed to use cvd rather that intscan since
it was found that intscan uses realscan and can lose some integers.
∂2/13/78 -- tab bug fixed
When the iosail package was brought from lots tabs were changed to spaces,
hence tabs were not passed over correctly in the input routine (eg. read
integer). This has been corrected.
∂2/7/78 -- new macros
R!C = record!class
R!P = record!pointer
∂1/30/78 -- openread / openwrite fixed
if on opening a filename, that file does not exist then iosail
now will permit the user to change device as well as file name.
∂1/26/78 -- availability of rdtty
RDTTY is now available for use by the user of IOSAIL.
∂1/26/78 -- rdtty correction
RDTTY now prompts with OUTSTR to the terminal which ignores
the status of setprint.
∂1/26/78 -- prompt changes
Instead of prompting with ?>integer> IOSAIL now prompts with ?>(integer)
and similarly for other types.
∂1/26/78 -- new READ
READ is no longer a synonym for READREAL. If the prompting is still the
default then READ will prompt with >? instead of ?>. This is for
compatibility with Floyd's notes.
∂1/26/78 -- READBUFFER
a new string procedure that returns anything left in the input buffer.
∂1/23/78 -- new macros
SPACE = " ".
NEWPAGE = FORMFEED.
∂1/23/78 -- rdtty
Rdtty has been incorporated into IOSAIL and setty has been eliminated.
Introduction.
This document describes the SAIL procedures and macros written
by Kevin Karplus <k.kjk> December 1977. The package is intended for the
CS105 and CS106 classes, but is available to all users of the SAIL
language. The package is being maintained at SU-AI by Brent Hailpern
(BTH). All bugs and suggetions should be sent to him.
To get all the macros and procedures declared, put the statement
REQUIRE "IOSAIL.HDR[SUB,SYS]" SOURCE!FILE;
in the declarations section of the outermost block of your SAIL program.
This will automatically include IOSAIL.REL[SUB,SYS] in the list of files
for the LOADER. The SAIL sources for the procedures are in
IOSAIL.SAI[SUB,SYS], the macros and declarations are in
IOSAIL.HDR[SUB,SYS].
There are several distinct parts to this package: macros whose
function is that of abbreviation, some macros for debugging, some simple
procedures for frequently used character tests, the input/output routines,
and some macros for use with SETPRINT.
SPACE,TAB,BELL,FORMFD,LF,CR,CRLF,!,PROC,REF,THRU,UPTO,BEGINLOOP.
(MACROS defined in IOSAIL.HDR[SUB,SYS])
The following are simple abbreviations that have proven useful
in the past.
Printing abbreviations:
TAB ==> a string containing the tab character.
SPACE ==> a string containing the space character.
BELL ==> a string containing the bell character.
FORMFEED ==> a string containing the formfeed character ↑L.
NEWPAGE = FORMFD = FORMFEED
LF = LINEFEED ==> a string containing the linefeed character.
CR ==> a string containing a carriage return.
CRLF = NEWLINE ==> the equivalent of CR & LF.
Stylistic abbreviations:
! ==> COMMENT
PROC ==> PROCEDURE
REF ==> REFERENCE
THRU ==> step 1 until
UPTO ==> :=1 step 1 until
BEGINLOOP ==> while true do begin
Record/Pointer abbreviations:
R!C ==> record!class
R!P ==> record!pointer
NEWR ==> new!record
NULLR ==> null!record
LOTS plotting commands (included for compatibility):
PLOTLF ==> a string containing ↑E & LINEFEED
Note that the BEGINLOOP macro along with the DONE construct can
be used as a looping construct of great power and simplicity. For
example:
beginloop "example loop"
temp:=READLINE;
if EOF then DONE "example loop";
! do here whatever you want with temp;
.
.
.
end "example loop";
this program fragment reads lines of the main input device until it
reaches an end of file. All the lines read are processed by the code
after the IF statement, and the the loop is terminated by satisfaction of
the end of file test. (The procedures READLINE and EOF are described
later.) The capitalization of the DONE statement is encouraged, to make
it stand out from the predominantly lower case program body.
Please remember that the macro for comment (!) must have a
delimiter after it to be recognized as a character. Thus "!ABCD" is a
legal variable, but "! ABCD" is a comment.
The usual uses of FORMFEED, TAB, BELL, and CRLF are with the
PRINT statement to print them on your terminal (or with similar statements
to add them to files). You will find CRLF the most useful of this set of
characters. FORMFEED at the begining of a line tells the line printer to
go to a new page before printing the line.
NULLSTRING,CVBS,ALPHA,NUMER,MEMLOC,LOWBOUND,UPBOUND,NUMDIM.
(MACROS defined in IOSAIL.HDR[SUB,SYS])
Some other macros of interest are
NULLSTRING(x) returns TRUE if the string x is the null string and
FALSE otherwise.
CVBS(x) converts boolean to string "TRUE" or "FALSE"
ALPHA ==> a string containing the entire alphabet in both
upper and lower cases.
NUMER ==> a string containing all the digits.
MEMLOC(x) ==> memory[location(x)]. (useful only to hackers)
LOWBOUND(arr,dim) returns the lower bound of the DIMth dimension of
the array ARR at runtime.
UPBOUND(arr,dim) returns the upper bound of the DIMth dimension of the
array ARR at runtime.
NUMDIM(arr) returns the number of dimensions of array ARR at
runtime.
ALPHA and NUMER have many uses, one of the most important being
to make it easier to set up "breaktables" for the SAIL SCAN statement.
Novices should not have to worry about this powerful but complicated
statement, as the routines described later should be sufficient for their
needs.
LOWBOUND, UPBOUND, and NUMDIM are useful if you use arrays with
variable dimensions, but need to know the dimensions at runtime to set
loop parameters. These macros are particularly useful inside of
procedures, which can then be handed arrays of any size and still be able
to figure out what to do with them. Note that NUMDIM will be negative for
string arrays (because of the expansion to the ARRINFO command).
DEBUG,BUGON,BUGOFF.
This is a very powerful macro originally designed by
J.Q.Johnson, later slightly modified by Kevin Karplus. It allows the user
to print out selected variables at any point in a program, along with
identification of the variables and the location in the program. The
output looks like:
DEBUG:after fiddling the foofram i=17.3; j=99.99; stq="jjjgh"jjitm";
which could have been created by a program segment like:
i:=17.3;
j:=99.99;
stq:="jjjgh""jjitm";
DEBUG(after fiddling the foofram,(i,j,stq));
Notice that the quote mark inside the string is not doubled by DEBUG, and
that the location identification is any string of characters that
satisfies the normal rules about arguments to macros. For simplicity, it
is best to keep this to a few short simple words, without commas or other
punctuation.
Like most macros, DEBUG gets confused by commas that it thinks
are superfluous or misplaced. Thus a statement like: DEBUG(before
input,(innersecrets[1,2,j])); is liable to give you an error message (or a
mysterious DRYROT). SAIL doesn't know about DEBUG, so the error message
will be exceedingly unhelpful. There is, of course, a way around. (SAIL
abounds in ways to get around things, it adds to its mystery.) The
particular hack involved is to put curly braces around the variable that
is causing the difficulty. Thus the statement DEBUG(before
input,({innersecrets[1,2,j]},j)); would work.
It is also possible to use expressions instead of variables as
the things to be printed. They will be printed as if they were in a PRINT
statement , and will be labeled with the expression that produced them.
Use of expressions is not guaranteed by the implementors, so don't get
upset if it doesn't work.
As a further convenience, if you have only a single variable to
print, you can omit the parentheses around it. "DEBUG(here,a);" should be
exactly the same as "DEBUG(here,(a));" .
Sometimes great quantities of debug output can be generated,
even when it is known that the bug you are looking for only occurs when
certain special conditions occur. While the computer cannot check the
phase of the moon or the absence of the TA, it is often easy to put in
checks to see whether the program has gotten a value that is strange at
some point, and then turn on the DEBUG statements. To make this easier,
two macros have been included: BUGON and BUGOFF. Normally the DEBUG
statements are "on" and print output on the terminal. Execution of BUGOFF
turns off the DEBUG statements until the next execution of a BUGON. Note
that the variable !bugoff is what is changed by these macros, you
shouldn't use that variable name for anything else. As an example, assume
that the routine BUGGY is known to die when it has to handle long strings.
Then something like this fragment might help:
BUGOFF;
. . .
if length(arg) > 56 then BUGON else BUGOFF;
BUGGY(arg);
. . .
There is also a more general and more powerful debugging
facility available, called BAIL. For most short student programs, the
effort involved in learning and using BAIL is not justified by the small
extra debugging power it gives you.
YES,NO,NUMERIC,LOWERCASE,UPPERCASE,ALPHABETIC,ALPHAMERIC.
Some small simple procedures for dealing with strings
This section contains a number of very short, very simple
procedures that are frequently useful. All are boolean procedures (ie.
they return either TRUE or FALSE).
The argument to all the procedures is a character. This can be
done either by having the character be the first character of a string
passed to the procedure, or by passing an integer whose value is the ASCII
representation of the character. Passing a string for interpretation of
its first character is probably more common for most of these procedures.
YES(char) returns TRUE if the character is "Y" or "y".
NO(char) returns TRUE if the character is "N" or "n".
NUMERIC(char) returns TRUE if the character is a decimal digit.
LOWERCASE(char) returns TRUE if the character is a lower case letter.
UPPERCASE(char) returns TRUE if the character is an upper case letter.
ALPHABETIC(char) returns TRUE if the character is a letter.
ALPHAMERIC(char) returns TRUE if the character is either a letter or a
digit.
CAPITALIZE.
CAPITALIZE(string) returns its string argument with all the lower case
letters converted to upper case (or, to be old fashioned,
all the miniscules converted to magiscules). Thus
CAPITALIZE("abcDEFmmm123 $ $") returns "ABCDEFMMM123 $ $".
Note that the argument is left unchanged.
ROUND.
The round procedure does floor(x+.5) despite the compile switch setting
for real to integer coersion (it uses the FIXR FAIL command).
To be used:
i:=round(x)
where i is integer and x is real.
A discussion of channels.
Whenever input and output are mentioned in respect to SAIL,
channels are almost certain to be mentioned. A channel (in this context)
is simply a small number that gets associated with the file or device you
are communicating with, so it isn't necessary to refer to the whole name
of the file and look for it each time you want to access it. The numbers
are rather arbitrarily assigned, and have no intrinsic meaning.
SAIL can handle about 16 channels (0 through 15) plus the
controlling terminal (also known as TTY:) as channel -1. Channel -2 is
also the terminal. The channels used by this package are the same as SAIL
channels except:
1. When inputing through the procedures of this package, channel
-1 means the "main reader channel". This is the terminal,
unless SETREADER is called to change it.
2. When inputting though the procedures of this package, channel
-2 means the controlling terminal.
3. All the SAIL functions behave as normal, do NOT try printing on
-1 nor should you try printing on channel -2. To output to the
terminal use PRINT.
4. The normal mechanisms for opening and closing files should
not be employed if the files are to be used with the other
routines of this package.
OPENREAD,OPENWRITE,CLOSEFILE,CLOSEALL.
The process of finding the file you want to use and associating
a channel number with it is called "opening a file". The similar process
of cleaning out the buffers and putting the file away when you are done is
called "closing a file".
There are two routines in IOSAIL for opening a file, called
OPENREAD and OPENWRITE. Both take the file name as an argument and both
return the channel associated with the file. If no filename is given, (or
if the null string is given) then the OPEN... procedures ask for the file
name from the teletype. Note that TTY: is an acceptable filename for
both input and output (it means the terminal you are running the program
from).
The format of the commands looks like:
chan:=OPENREAD;
chan:=OPENREAD("FOO.in");
chan:=OPENWRITE;
chan:=OPENWRITE("FOO.OUT");
Please resist the temptation to use the .SAI extension for your
output files. It is very easy to destroy programs that way.
The counterpart of "opening", "closing", is handled just as
easily. CLOSEFILE(chan) will close the file and free the channel number
for reassignment. CLOSEFILE(-1) will close the reader channel and return
channel -1 to its original status as the controlling input terminal.
There is a procedure CLOSEALL, which will close all the channels
that are open (including any setprint file), and generally try to set the
input output system as much like its initial state as it can. To do this
massive clean-up, make:
CLOSEALL;
the last executable statement of your program.
Filenames.
It is possible to determine the filename of a channel that has
been opened by use of the string procedure FILENAME(chan). If the channel
is connected to a terminal the string "TTY:" is returned.
The reads: LINE,INTEGER,REAL,STRING,WORD,YESNO,BUFFER,READ,RDTTY.
Procedures for input
There are several procedures for inputting various values from a
channel. All of them have the same basic calling sequence, and behave in
similar manners (except for RDTTY which is described below). They are:
READLINE, READINTEGER, READREAL, READSTRING, READWORD, READYESNO, READ,
READBUFFER.
The calling sequence is
foo:=READ...(chan);
foo:=READ...;
where READ... means any of the READ routines mentioned above, and foo is
of the appropriate type for the particular routine. If chan is given,
then the channel must be open for reading. If chan is not given, -1 is
assumed and reading is from the reader channel.
READLINE is the most basic of these routines, and is called by
all the others. It reads a line (ignoring carriage return) until it finds
a linefeed, or end-of-file is reached. If there are no more lines to be
read from the file, a null string is returned, otherwise the string read
(without crlf) is returned.
READINTEGER and READREAL ignore blank, tabs, and crlfs until
they get to a non-blank character. If the character is not acceptable for
the first character of a number, an error message is generated. If the
channel is connected to a terminal, then the user is prompted for a retry.
Otherwise the error is fatal, and the program aborts.
READ is the same as READREAL except that if the prompting on the
channel is the default then the prompting for that particular read becomes
>? instead of ?>.
READSTRING reads a string beginning and ending with the quote
character ("). A quote can be included in the string by doubling it.
Thus the string "abc""DEF""ghi" would be read as abc"DEF"ghi . Blanks,
tabs, and crlfs before the opening " are ignored. If the first character
after the blanks is not a quote, an error message is printed. (Again,
fatal if not TTY, retry if TTY).
READWORD reads the next punctuation mark or string of alphameric
characters. Leading blanks, tabs, and crlfs are ignored.
READYESNO expects the next character (after blanks, tabs, and
crlfs) to be "Y","y", "N", or "n". It then returns TRUE if it is a y and
FALSE if it is an n. Any other character results in an error. (Fatal if
not a TTY, retry if a tty).
READBUFFER returns the unread portion of the input buffer as a
string.
RDTTY is called by RDTTY("prompt"), where ">" is default. It
prints that prompt on the terminal (ignoring SETPRINTs) and then reads a
line from the terminal and returns it as a string. RDTTY is faster in
that it avoids all overhead of READLINE(-2) and permits direct
specification of the prompt. Its drawback is that it bypasses the eof
mechanism for the terminal and should therefore be used with care.
Note: READLINE always reads a fresh line from the terminal or
file, all the other routines will keep reading on the same line until
there is nothing left of the line, or a READLINE is done. Thus it is
possible to read every non-blank of a file with repeated READWORD, or
every number with READREAL. Line numbers in files are ignored.
EOF.
End-of-file handling
When one of the READ... routines is called, and can't find
anymore input, it returns an appropriate null value. (Null strings for
string valued procedures, FALSE for READYESNO, and intscan(null) or
realscan(null) for READINTEGER and READREAL). The EOF indication can be
tested with the procedure EOF(chan). As with all the procedures, if the
channel number is omitted, channel -1 s assumed. EOF will return TRUE,
after the call which returned the null value.
Thus the correct test for end-of-file is:
BEGINLOOP "readloop"
temp:=READ...;
if EOF then DONE "readloop";
! body of loop;
.
.
.
END "readloop"
Testing for end-of-file should be done after every read. An
end-of-file for display can be accomplished by typing <control><meta><lf>
(or <ctrl>z from a TTY). However, only one null return is made,
subsequent calls to read from a channel associated with a terminal will
behave normally, and EOF will only return TRUE if the last read on the
channel hit the EOF character.
GETPROMPT,SETPROMPT.
Prompting
When reading from the terminal, the user is prompted for input.
The default prompt for channels -2 and -1 is "?>", for the other channels
it is the channel number followed by ">". The prompt string can be
determined by foo:=GETPROMPT(chan), and changed by SETPROMPT(string,chan).
If the channel is not specified, then channel -1 is assumed. If
the string to SETPROMPT is null then the prompt will be set back to the
default.
If the promptstring for a channel is the default string, then
the routines READINTEGER, READREAL, READSTRING, READWORD, READYESNO add a
further prompt to indicate what type of input is being requested.
SETREADER,GETREADER.
The use of channel -1 to access the main reader channel has been
mentioned before. To associate -1 with some real channel is very easy.
First, OPENREAD should be called to create the channel, then
SETREADER(chan) will make chan the main reader channel. The reader
channel can be reset to the terminal (the initial state) by doing
SETREADER(-1). SETREADER without an argument is equivalent to
SETREADER(-1).
GETREADER is an integer valued procedure with no arguments which
returns the channel number of the main reader channel. If no SETREADER
call has been made, then GETREADER returns -1.
SETECHO.
Echoing
All the input through the main reader channel can be echoed to a
file, or to the terminal. This is accomplished by doing an OPENWRITE to
open a channel, and SETECHO(chan) to send the echoing to the channel.
SETECHO(-1) or SETECHO without arguments, turns off the echoing. The echo
can be forced to the terminal by SETECHO(-2).
Note that you cannot echo to the file used in a SETPRINT
statement, because of the way SAIL handles SETPRINT. However, it is
possible to do CPRINT to the same channel as the echoing.
TERM!PRINT!(ON | OFF),FILE!PRINT!(ON | OFF),FILE!PRINT!CLOSE.
Setprint control macors and procedures
There are two macros and three procedures in this class, and
they all invoke SETPRINT with various arguments. They serve to direct
your PRINT output to your terminal, a file, or both. Normally your PRINT
output goes just to your terminal, so you have to do something special if
you want the output to go to a file as well. You could open a channel and
write to it (using OPENWRITE and CPRINT), but this necessitates
duplicating the PRINT statements and is often not worth the trouble.
First the file should be established with the
SETPRINT(filename,"B"); statement as described int the SAIL manual.
Thereafter TERM!PRINT!ON, TERM!PRINT!OFF, FILE!PRINT!ON, FILE!PRINT!OFF,
FILE!PRINT!CLOSE should suffice for handling the various SETPRINT options.
Note: the FILE!PRINT!... identifiers are actually macros
calling the three procedures !!FPON,!!FPOFF,!!FPC so avoid using these
bang-bang (!!) identifiers as variables in your programs.